/**
 * Copyright (C) 2021 - 2031 O-Cubes Co., Ltd.
 */

/****************************************************************
 *  @file    common.h
 *  @brief   Common operation header file
 *  @version v1.0
 *  @date    03. Apr. 2023
 ****************************************************************/

#ifndef __COMMON_H__
#define __COMMON_H__

#include <stdint.h>
#include <stddef.h>
#include <machine/endian.h>
#include "types.h"
#include "autoconf.h"
#include "config_p1.h"

#ifdef __cplusplus
extern "C" {
#endif

/* Compiler related */
#ifndef __always_static_inline
#define __always_static_inline __attribute__((always_inline)) static inline
#endif

#ifndef __static_inline
#define __static_inline static inline
#endif

#ifndef __no_inline
#define __no_inline __attribute__((noinline))
#endif

#ifndef __weak
#define __weak __attribute__((weak))
#endif

#ifndef __noreturn
#define __noreturn __attribute__((__noreturn__))
#endif

#ifndef __used
#define __used __attribute__((used))
#endif

#ifndef __maybe_unused
#define __maybe_unused __attribute__((unused))
#endif

#ifndef __section
#define __section(S) __attribute__((section(S)))
#endif

#ifndef __packed
#define __packed __attribute__((packed))
#endif

#ifndef __naked
#define __naked __attribute__((naked))
#endif

#ifndef __asm__
#define __ams__ __asm
#endif

#ifndef __packed
#define __packed __attribute__((packed, aligned(1)))
#endif

#ifndef __packed_struct
#define __packed_struct struct __attribute__((packed, aligned(1)))
#endif

#ifndef __packed_union
#define __packed_union union __attribute__((packed, aligned(1)))
#endif

#if defined(SPIFLASH_XIP_EN)
#define __ATTR_RAM_CODE __attribute__((section(".ram.code")))
#else
#define __ATTR_RAM_CODE
#endif

#define __align(n) __attribute__((aligned(n)))
#define __linkto(f) __attribute__((alias(#f)))

#ifndef TRUE
#define TRUE   1U
#endif
#ifndef FALSE
#define FALSE  0U
#endif
#ifndef NULL
#define NULL   0U
#endif

#define PTR_TO_U32(ptr)      ((u32)(long)ptr)

#define ARRAY_SIZE(array)        (sizeof(array)/sizeof(array[0]))
#define GET_OFFSET_OF_ADDR(BASE, TYPE, MEMBER) (BASE + offsetof(TYPE, MEMBER))
#define swap(a, b) \
		do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)

#define DO_DIV(n, base)      ({       \
	u32 __base = (base);          \
	u32 __rem;                    \
	__rem = ((u64)(n)) % __base;  \
	(n) = ((u64)(n)) / __base;    \
	__rem;                        \
	})

#define DIV_ROUND_UP(n, d)   (((n) + (d) - 1) / (d))

#define TIME_MS_VAL          1000
#define TIME_US_VAL          1000000

#if __BYTEORDER == __LITTLE_ENDIAN
#define cpu_to_be16(x)		__bswap16(x)
#define cpu_to_be32(x)		__bswap32(x)
#define cpu_to_be64(x)		__bswap64(x)
#define be16_to_cpu(x)		__bswap16(x)
#define be32_to_cpu(x)		__bswap32(x)
#define be64_to_cpu(x)		__bswap64(x)
#define cpu_to_le16(x)		(x)
#define cpu_to_le32(x)		(x)
#define cpu_to_le64(x)		(x)
#define le16_to_cpu(x)		(x)
#define le32_to_cpu(x)		(x)
#define le64_to_cpu(x)		(x)
#else /* if __BYTEORDER == __LITTLE_ENDIAN */
#define cpu_to_be16(x)		(x)
#define cpu_to_be32(x)		(x)
#define cpu_to_be64(x)		(x)
#define be16_to_cpu(x)		(x)
#define be32_to_cpu(x)		(x)
#define be64_to_cpu(x)		(x)
#define cpu_to_le16(x)		__bswap16(x)
#define cpu_to_le32(x)		__bswap32(x)
#define cpu_to_le64(x)		__bswap64(x)
#define le16_to_cpu(x)		__bswap16(x)
#define le32_to_cpu(x)		__bswap32(x)
#define le64_to_cpu(x)		__bswap64(x)
#endif /* if __BYTEORDER == __LITTLE_ENDIAN */

#define min(x, y) ({					\
		typeof(x) _min1 = (x);			\
		typeof(y) _min2 = (y);			\
		(void) (&_min1 == &_min2);		\
		_min1 < _min2 ? _min1 : _min2; })

#define max(x, y) ({					\
		typeof(x) _max1 = (x);			\
		typeof(y) _max2 = (y);			\
		(void) (&_max1 == &_max2);		\
		_max1 > _max2 ? _max1 : _max2; })

#define min3(x, y, z) min((typeof(x))min(x, y), z)
#define max3(x, y, z) max((typeof(x))max(x, y), z)

static inline u16 __get_unaligned_be16(const u8 *p)
{
	return p[0] << 8 | p[1];
}

static inline u32 __get_unaligned_be32(const u8 *p)
{
	return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
}


static inline void __put_unaligned_be16(u16 val, u8 *p)
{
	*p++ = val >> 8;
	*p++ = val;
}

static inline void __put_unaligned_be32(u32 val, u8 *p)
{
	__put_unaligned_be16(val >> 16, p);
	__put_unaligned_be16(val, p + 2);
}

static inline u16 get_unaligned_be16(const void *p)
{
	return __get_unaligned_be16(p);
}

static inline u32 get_unaligned_be32(const void *p)
{
	return __get_unaligned_be32(p);
}

static inline void put_unaligned_be16(u16 val, void *p)
{
	__put_unaligned_be16(val, p);
}

static inline void put_unaligned_be32(u32 val, void *p)
{
	__put_unaligned_be32(val, p);
}

static inline u16 __get_unaligned_le16(const u8 *p)
{
	return p[0] | p[1] << 8;
}

static inline u32 __get_unaligned_le32(const u8 *p)
{
	return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
}

static inline void __put_unaligned_le16(u16 val, u8 *p)
{
	*p++ = val;
	*p++ = val >> 8;
}

static inline void __put_unaligned_le32(u32 val, u8 *p)
{
	__put_unaligned_le16(val >> 16, p + 2);
	__put_unaligned_le16(val, p);
}

static inline u16 get_unaligned_le16(const void *p)
{
	return __get_unaligned_le16(p);
}

static inline u32 get_unaligned_le32(const void *p)
{
	return __get_unaligned_le32(p);
}

static inline void put_unaligned_le16(u16 val, void *p)
{
	__put_unaligned_le16(val, p);
}

static inline void put_unaligned_le32(u32 val, void *p)
{
	__put_unaligned_le32(val, p);
}

#ifdef __cplusplus
}
#endif

#endif /* __COMMON_H__ */
